﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data.Linq;
using System.Globalization;
using System.IO;
using System.Linq.Dynamic;
using System.Linq;
using System.Text;

namespace IntraVision.Web
{
    public delegate void EntityControllerEvent(object context, object entity);

    /// <summary>
    /// Контроллер для вывода списка сущностей. Минимальные возможности по поиску и сортировке.
    /// Упрощенная версия TableController.
    /// </summary>
    /// <typeparam name="TEntity">Тип сущностей</typeparam>
    /// <typeparam name="TDataContext">Контекст</typeparam>
    public class ReadOnlyEntityController<TEntity, TDataContext> : ControllerBase
        where TEntity : class, new()
        where TDataContext : DataContext, new()
    {
        protected virtual void EntityLoaded(TDataContext dc, TEntity entity) {}
        protected virtual void BeforeLoadList(TDataContext dc){}
        
        /// <summary>
        /// Вывод списка TEntity
        /// </summary>
        public virtual void List()
        {
            if (string.IsNullOrEmpty(TemplatePath)) TemplatePath = "~/views/" + Name + "/list.haml";
            if (string.IsNullOrEmpty(LayoutPath) && string.IsNullOrEmpty(Request["nolayout"])) LayoutPath = "~/views/layouts/page.haml";

            RegisterTableScripts();

            using (var dc = new TDataContext())
            {
                BeforeLoadList(dc);

                if (!string.IsNullOrEmpty(Request["json"]))
                {
                    IQueryable<TEntity> list = dc.GetTable<TEntity>();
                    if (!string.IsNullOrEmpty(Request["where"]))
                        list = list.Where(Request["where"]);
                    if (!string.IsNullOrEmpty(Request["search"]))
                        list = list.Where(LINQHelper.GenerateSearchString(typeof(TEntity)), Request["search"]);
                    if (!string.IsNullOrEmpty(Request["orderby"]))
                        list = list.OrderBy(Request["orderby"]);
                    TEntity[] entities = list.ToArray();
                    RenderJSON(entities);
                }
                else
                {
                    IQueryable<TEntity> list = dc.GetTable<TEntity>() as IQueryable<TEntity>;
                    if (!string.IsNullOrEmpty(Request["search"]))
                        list = list.Where(LINQHelper.GenerateSearchString(typeof(TEntity)), Request["search"]);
                    if (!string.IsNullOrEmpty(Request["orderby"]))
                        list = list.OrderBy(Request["orderby"]);
                    list = CustomFilter(dc, list);

                    ViewData["orderby"] = Request["orderby"];
                    ViewData["search"] = Request["search"];
                    ViewData["entities"] = new ReadOnlyCollection<TEntity>(list.ToList());

                    if (Session[Name + "_changed"] != null)
                    {
                        ViewData["changedId"] = Session[Name + "_changed"];
                        Session[Name + "_changed"] = null;
                    }

                    RenderView();
                }
            }
        }

        public virtual void View(string entityid)
        {
            if (string.IsNullOrEmpty(TemplatePath)) TemplatePath = "~/views/" + Name + "/form.haml";
            if (string.IsNullOrEmpty(LayoutPath) && string.IsNullOrEmpty(Request["nolayout"])) LayoutPath = "~/views/layouts/page.haml";

            using (TDataContext dc = new TDataContext())
            {
                int id = 0;
                TEntity entity = null;
                try
                {
                    if (!Int32.TryParse(entityid, out id))
                        throw new IntraVisionWebException(404);

                    entity = dc.GetTable<TEntity>().Where("Id = @0", id).FirstOrDefault();

                    if (entity == null)
                        throw new IntraVisionWebException(404);

                    EntityLoaded(dc, entity);
                }
                catch (IntraVisionWebException ex)
                {
                    throw ex;
                }
                catch (Exception ex)
                {
                    ViewData.Exceptions.Add(ex);
                }

                if (!string.IsNullOrEmpty(Request["json"]))
                {
                    if (entity != null)
                        RenderJSON(entity);
                    else
                        RenderJSON(new AJAXResult(new ArgumentOutOfRangeException("Объект не найден в базе данных.")));
                }
                else
                {
                    //Восстановить текущую закладку
                    if (!string.IsNullOrEmpty(Request["tab"])) ViewData["tab"] = Request["tab"];

                    ViewData["entity"] = entity;
                    RenderView();
                }
            }
        }

        public virtual TEntity GetEntity(TDataContext dc, int id)
        {
            return GetEntity(dc, id.ToString());
        }

        public virtual TEntity GetEntity(TDataContext dc, string id)
        {
            int eid = 0;
            if (String.IsNullOrEmpty(id) || !Int32.TryParse(id, out eid) || eid == 0) return null;
            return dc.GetTable<TEntity>().Where("Id=@0", eid).Single();
        }

        protected virtual IQueryable<TEntity> CustomFilter(TDataContext dc, IQueryable<TEntity> query)
        {
            return query;
        }

        /// <summary>
        /// Зарегистрировать скрипты для таблицы
        /// </summary>
        public virtual void RegisterTableScripts()
        {
            RegisterScript("table.js", "jquery.multipleselect.js", "jquery.autocomplete.js");
            RegisterStylesheet("autocomplete/autocomplete.css");

            //Добавление скрипта с именем ~/js/<ControllerName>/list.js, если он существует
            string jspath = Server.MapPath(string.Format(CultureInfo.InvariantCulture, "~/js/{0}/table.js", Name));
            if (File.Exists(jspath))
                RegisterScript(string.Format(CultureInfo.InvariantCulture, "{0}/table.js", Name));

            //Добавление стиля с именем ~/css/<ControllerName>/list.css, если он существует
            string csspath = Server.MapPath(string.Format(CultureInfo.InvariantCulture, "~/css/{0}/table.css", Name));
            if (File.Exists(csspath))
                RegisterStylesheet(string.Format(CultureInfo.InvariantCulture, "{0}/table.css", Name));
        }
    }
}
